package stone926.mods.more_enchantments.spawn;

import net.fabricmc.fabric.mixin.object.builder.VillagerTypeAccessor;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.mob.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionUtil;
import net.minecraft.util.DyeColor;
import net.minecraft.util.Util;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.registry.Registry;
import net.minecraft.village.VillagerData;
import net.minecraft.village.VillagerProfession;
import net.minecraft.village.VillagerType;
import net.minecraft.world.World;
import stone926.mods.more_enchantments.MoreEnchantmentsMod;
import stone926.mods.more_enchantments.interfaces.*;
import stone926.mods.more_enchantments.mixins.accessors.CreeperAccessor;
import stone926.mods.more_enchantments.mixins.accessors.MagmaCubeEntityAccessor;
import stone926.mods.more_enchantments.mixins.accessors.ShulkerEntityAccessor;
import stone926.mods.more_enchantments.spawn.trade.ZombieVillagerTradeOffers;
import stone926.mods.more_enchantments.util.EnchantmentUtil;
import stone926.mods.more_enchantments.util.EntityUtil;
import stone926.mods.more_enchantments.util.RandomUtil;

import static net.minecraft.entity.attribute.EntityAttributes.*;

public final class EntityInitializers {

  public static final EntityInitializer<CreeperEntity> CREEPER = (creeper, random) -> {
    EntityUtil.modifyAttribute(creeper, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "creeper.speed",
      1D + random.nextDouble(),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    EntityUtil.modifyAttribute(creeper, GENERIC_FOLLOW_RANGE, new EntityAttributeModifier(
      "creeper.followRange",
      random.nextInt(100),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(creeper, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "creeper.maxHealth",
      1.5D + random.nextInt(11),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    RandomUtil.runIfPossible(0.3, random, () -> {
      creeper.addStatusEffect(new StatusEffectInstance(StatusEffects.INVISIBILITY, 99999, 1, true, true));
    });
    ((CreeperAccessor) creeper).setFuseTime(RandomUtil.nextInt(1, 5, random));
    ((CreeperAccessor) creeper).setExplosionRadius(RandomUtil.nextInt(4, 8, random) + (RandomUtil.isPossible(0.1, random) ? 5 : 0));
    ((ICreeperEntity) creeper).setDestructionTypeNone(true);
  };

  public static final EntityInitializer<AbstractSkeletonEntity> SKELETON_USING_BOW = (skeleton, random) -> {
    EquipmentFitter.equipBow(skeleton, random);
    EquipmentFitter.equipArmor(skeleton, random);
    skeleton.setEquipmentDropChance(EquipmentSlot.MAINHAND, 0.3F);
    EntityUtil.modifyAttribute(skeleton, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "skeleton.speed",
      random.nextDouble() / 3.5,
      EntityAttributeModifier.Operation.ADDITION
    ));
  };

  public static final EntityInitializer<AbstractSkeletonEntity> SKELETON_USING_WEAPON = (skeleton, random) -> {
    EntityUtil.modifyAttribute(skeleton, GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(
      "skeleton.damage",
      RandomUtil.nextInt(8, 27, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(skeleton, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "skeleton.maxHealth",
      RandomUtil.nextInt(2, 4, random),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    EntityUtil.modifyAttribute(skeleton, GENERIC_ARMOR, new EntityAttributeModifier(
      "skeleton.armor",
      20 + random.nextInt(15),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(skeleton, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "skeleton.speed",
      random.nextDouble() / 2.35,
      EntityAttributeModifier.Operation.ADDITION
    ));
    EquipmentFitter.equipArmor(skeleton, random);
    EquipmentFitter.equipWeaponForSkeleton(skeleton, random);
    EntityUtil.addExperiencePoints(skeleton, 12 + random.nextInt(19));
  };

  public static final EntityInitializer<WitchEntity> WITCH = (witch, random) -> {
    EntityUtil.modifyAttribute(witch, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "witch.maxHealth1",
      random.nextInt((int) witch.getMaxHealth() * 3 + 1),
      EntityAttributeModifier.Operation.ADDITION
    ));
    Potion potion = stone926.mods.more_enchantments.util.potion.PotionUtil.selectRandomPotion(random);
    ItemStack potionType = switch (random.nextInt(4)) {
      case 0 -> new ItemStack(Items.LINGERING_POTION);
      case 1 -> new ItemStack(Items.SPLASH_POTION);
      default -> new ItemStack(Items.POTION);
    };
    EntityUtil.equipStackAndSetDropChance(witch, EquipmentSlot.HEAD, PotionUtil.setPotion(potionType, potion), 1);
    witch.setEquipmentDropChance(EquipmentSlot.MAINHAND, 0.3F);
  };

  public static final EntityInitializer<WitchEntity> WITCH_DROPS_CORNEL = (witch, random) -> {
    WITCH.initialize(witch, random);
    EntityUtil.equipStackAndSetDropChance(witch, EquipmentSlot.FEET, new ItemStack(MoreEnchantmentsMod.CORNEL_ITEM), 0.5F);
    EquipmentFitter.equipArmorForWitch(witch, random);
    ((IWitch) witch).setStrengthened(true);
    EntityUtil.modifyAttribute(witch, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "witch.maxHealth2",
      RandomUtil.nextInt(2, 5, random),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    witch.addStatusEffect(new StatusEffectInstance(StatusEffects.RESISTANCE, 20 * 20, 5));
  };

  public static final EntityInitializer<WitherSkeletonEntity> WITHER_SKELETON = (witherSkeleton, random) -> {
    ItemStack mainhand = EnchantmentUtil.enchant(RandomUtil.isPossible(3, random) ? new ItemStack(Items.STONE_SWORD) : new ItemStack(Items.NETHERITE_SWORD), MobEnchantmentMaps.WITHER_SKELETON_WEAPON(), random);
    EntityUtil.equipStackAndSetDropChance(witherSkeleton, EquipmentSlot.MAINHAND, mainhand, 0.2F);
    RandomUtil.runIfPossible(3, random, () -> EntityUtil.equipStackAndSetDropChance(witherSkeleton, EquipmentSlot.FEET, EnchantmentUtil.enchant(
      new ItemStack(Items.NETHERITE_BOOTS), Enchantments.SOUL_SPEED, 1 + random.nextInt(4)
    ), 0.1F + random.nextFloat()));
    EntityUtil.modifyAttribute(witherSkeleton, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "witherSkeleton.speed",
      random.nextDouble() / 3,
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(witherSkeleton, GENERIC_FOLLOW_RANGE, new EntityAttributeModifier(
      "witherSkeleton.followRange",
      1 + random.nextInt(10),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    EntityUtil.addExperiencePoints(witherSkeleton, 20 + random.nextInt(21));
  };

  public static final EntityInitializer<PiglinEntity> PIGLIN = EquipmentFitter::equipArmorForPiglin;

  public static final EntityInitializer<PiglinBruteEntity> PIGLIN_BRUTE_BASTION_REMNANT = (piglin, random) -> {
    ItemStack mainhand = EnchantmentUtil.enchant(new ItemStack(Items.GOLDEN_AXE), MobEnchantmentMaps.WEAPON(), random);
    EntityUtil.equipStackAndSetDropChance(piglin, EquipmentSlot.MAINHAND, mainhand, 0.3F);
    EntityUtil.modifyAttribute(piglin, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "piglin.maxHealth",
      random.nextInt((int) piglin.getMaxHealth() * 2 + 1),
      EntityAttributeModifier.Operation.ADDITION
    ));
  };

  public static final EntityInitializer<PiglinBruteEntity> PIGLIN_BRUTE = (piglin, random) -> {
    EntityUtil.equipStackAndSetDropChance(piglin, EquipmentSlot.MAINHAND, new ItemStack(Items.GOLDEN_AXE), 0);
    EntityUtil.equipStackAndSetDropChance(piglin, EquipmentSlot.OFFHAND, new ItemStack(Items.ENCHANTED_GOLDEN_APPLE), 1);
  };

  public static final EntityInitializer<PillagerEntity> PILLAGER = (pillager, random) -> {
    ItemStack crossbow = new ItemStack(Items.CROSSBOW);
    EnchantmentUtil.enchant(crossbow, MobEnchantmentMaps.CROSSBOW(), random);
    EntityUtil.equipStackAndSetDropChance(pillager, EquipmentSlot.MAINHAND, crossbow, 0.5F);
    EntityUtil.modifyAttribute(pillager, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "pillager.maxHealth",
      random.nextInt((int) pillager.getMaxHealth()),
      EntityAttributeModifier.Operation.ADDITION
    ));
  };

  public static final EntityInitializer<VindicatorEntity> VINDICATOR = (vindicator, random) -> {
    ItemStack ironAxe = EnchantmentUtil.enchant(
      new ItemStack(Items.IRON_AXE), Enchantments.SHARPNESS, RandomUtil.nextInt(7, 20, random)
    );
    EntityUtil.equipStackAndSetDropChance(vindicator, EquipmentSlot.MAINHAND, ironAxe, 0.1F);
    EntityUtil.modifyAttribute(vindicator, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "vindicator.maxHealth",
      random.nextInt((int) vindicator.getMaxHealth()),
      EntityAttributeModifier.Operation.ADDITION
    ));
  };

  public static final EntityInitializer<EvokerEntity> EVOKER = (evoker, random) -> EntityUtil.modifyAttribute(evoker, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
    "evoker.maxHealth",
    random.nextInt((int) evoker.getMaxHealth() * 2),
    EntityAttributeModifier.Operation.ADDITION
  ));

  public static final EntityInitializer<IllusionerEntity> ILLUSIONER = (illusioner, random) -> {
    EntityUtil.modifyAttribute(illusioner, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "illusioner.maxHealth",
      random.nextInt((int) illusioner.getMaxHealth()),
      EntityAttributeModifier.Operation.ADDITION
    ));
    RandomUtil.runFunctionsIfPossible(
      0.55, random,
      () -> illusioner.addStatusEffect(new StatusEffectInstance(StatusEffects.INVISIBILITY, 300, 1)),
      () -> illusioner.addStatusEffect(new StatusEffectInstance(StatusEffects.RESISTANCE, 3000, RandomUtil.nextInt(3, 4, random)))
    );
  };

  public static final EntityInitializer<ShulkerEntity> SHULKER = (shulker, random) -> {
    DyeColor[] dyeColors = DyeColor.values();
    ((ShulkerEntityAccessor) shulker).invokeSetColor(dyeColors[random.nextInt(dyeColors.length)]);
    EntityUtil.modifyAttribute(shulker, GENERIC_ARMOR, new EntityAttributeModifier(
      "Mandala Shulker Armor",
      RandomUtil.nextInt(10, 30, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(shulker, GENERIC_ARMOR_TOUGHNESS, new EntityAttributeModifier(
      "Mandala Shulker Armor Toughness",
      RandomUtil.nextInt(10, 20, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.equipStackAndSetDropChance(
      shulker, EquipmentSlot.CHEST, EnchantmentUtil.enchant(
        new ItemStack(Items.NETHERITE_CHESTPLATE), MoreEnchantmentsMod.PURGE,
        RandomUtil.nextInt(7, 9, random)
      ), 0
    );
    ((IShulkerEntity) shulker).setLevitationAmplifier(RandomUtil.nextInt(0, 2, random));
  };

  public static final EntityInitializer<ShulkerEntity> SHULKER_HAS_TREASURE = (shulker, random) -> {
    SHULKER.initialize(shulker, random);
    EquipmentFitter.equipShulkerBox(shulker, random);
    EquipmentFitter.equipElytra(shulker, random);
    EntityUtil.equipStackAndSetDropChance(
      shulker, EquipmentSlot.LEGS, EnchantmentUtil.enchant(
        new ItemStack(Items.NETHERITE_LEGGINGS), MoreEnchantmentsMod.FATE,
        RandomUtil.nextInt(1, 5, random)
      ), 0
    );
    ((IShulkerEntity) shulker).setLevitationAmplifier(RandomUtil.nextInt(3, 4, random));
  };

  public static final EntityInitializer<MobEntity> HOGLIN = (hoglin, random) -> {
    EntityUtil.modifyAttribute(hoglin, GENERIC_ATTACK_KNOCKBACK, new EntityAttributeModifier(
      "hoglin.attackKnockback",
      1 + random.nextFloat(),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    EntityUtil.modifyAttribute(hoglin, GENERIC_KNOCKBACK_RESISTANCE, new EntityAttributeModifier(
      "hoglin.knockbackResistance",
      random.nextFloat(),
      EntityAttributeModifier.Operation.ADDITION
    ));
  };

  public static final EntityInitializer<MobEntity> EMPTY = (mob, random) -> { };

  public static final EntityInitializer<VexEntity> VEX = (vex, random) -> {
    int cnt = RandomUtil.nextInt(10, 20, random);
    double x = vex.getX();
    double y = vex.getY();
    double z = vex.getZ();
    World world = vex.getEntityWorld();
    for (int i = 0; i < cnt; i++) {
      VexEntity v = (VexEntity) vex.getType().create(world);
      if (v != null) {
        v.setPosition(x + random.nextGaussian(), y + 0.5, z + random.nextGaussian());
        ItemStack ironSword = new ItemStack(Items.IRON_SWORD);
        ironSword.addEnchantment(Enchantments.FIRE_ASPECT, RandomUtil.nextInt(1, 5, random));
        ironSword.addEnchantment(Enchantments.KNOCKBACK, RandomUtil.nextInt(1, 6, random));
        EntityUtil.equipStackAndSetDropChance(v, EquipmentSlot.MAINHAND, ironSword, 0.2F);
        v.setVelocity(random.nextDouble() / 4D, random.nextDouble() / 5D, random.nextDouble() / 4D);
        v.setLifeTicks(RandomUtil.nextInt(80, 700, random));
        ((IEntitySpawnedByFlower) v).setSpawnedByMandala(true);
        world.spawnEntity(v);
      }
    }
    ItemStack ironSword = EnchantmentUtil.enchant(new ItemStack(Items.IRON_SWORD), Enchantments.FIRE_ASPECT, RandomUtil.nextInt(1, 5, random));
    EntityUtil.equipStackAndSetDropChance(vex, EquipmentSlot.MAINHAND, ironSword, 0.2F);
  };

  public static final EntityInitializer<ZombifiedPiglinEntity> ZOMBIFIED_PIGLIN = (zombifiedPiglin, random) -> {
    RandomUtil.runIfPossible(0.2, random, () -> zombifiedPiglin.setBaby(true));
    EquipmentFitter.equipArmorForZombifiedPiglin(zombifiedPiglin, random);
    EquipmentFitter.equipWeaponForZombifiedPiglin(zombifiedPiglin, random);
    zombifiedPiglin.setCanBreakDoors(true);
    EntityUtil.modifyAttribute(zombifiedPiglin, GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(
      "zombifiedPiglin.damage",
      3 + random.nextInt(7) + random.nextInt(2),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(zombifiedPiglin, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "zombifiedPiglin.speed",
      random.nextDouble() / 4.3,
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(zombifiedPiglin, ZOMBIE_SPAWN_REINFORCEMENTS, new EntityAttributeModifier(
      "zombifiedPiglin.reinforcements",
      1,
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.addExperiencePoints(zombifiedPiglin, 3 + random.nextInt(7));
  };

  public static final EntityInitializer<EndermanEntity> ENDERMAN_DRAGON_FIGHT = (enderman, random) -> {
    EntityUtil.modifyAttribute(enderman, EntityAttributes.GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "enderman.dragonFight.maxHealth",
      RandomUtil.nextInt(20, 80, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(enderman, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "enderman.dragonFight.speed",
      1.4,
      EntityAttributeModifier.Operation.MULTIPLY_BASE
    ));
    EntityUtil.modifyAttribute(enderman, GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(
      "enderman.dragonFight.attackDamage",
      MathHelper.nextFloat(enderman.getRandom(), 2, 3),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    PlayerEntity closestPlayer = enderman.getEntityWorld().getClosestEntity(
      PlayerEntity.class, TargetPredicate.DEFAULT, enderman,
      enderman.getX(), enderman.getY(), enderman.getZ(),
      Box.from(enderman.getPos()).expand(30)
    );
    if (closestPlayer != null) {
      enderman.setTarget(closestPlayer);
      enderman.setAngerTime(RandomUtil.nextInt(100 * 20, 300 * 20, random));
    }
  };

  public static final EntityInitializer<EndermanEntity> ENDERMAN = (enderman, random) -> {
    if (RandomUtil.isPossible(0.4, random)) {
      enderman.discard();
    } else {
      if (RandomUtil.isPossible(0.8, random)) {
        EntityUtil.equipStackAndSetDropChance(
          enderman, EquipmentSlot.HEAD,
          random.nextBoolean() ? new ItemStack(Items.CHORUS_FLOWER) : new ItemStack(Items.CHORUS_PLANT),
          1
        );
      }
      if (RandomUtil.isPossible(0.3, random)) {
        PlayerEntity closestPlayer = enderman.getEntityWorld().getClosestEntity(
          PlayerEntity.class, TargetPredicate.DEFAULT, enderman,
          enderman.getX(), enderman.getY(), enderman.getZ(),
          Box.from(enderman.getPos()).expand(25)
        );
        if (closestPlayer != null) {
          enderman.setTarget(closestPlayer);
          enderman.setAngerTime(RandomUtil.nextInt(10 * 20, 20 * 20, random));
        }
      }
    }
  };

  private static final EntityInitializer<ZombieEntity> ZOMBIE_BASE = (zombie, random) -> {
    RandomUtil.runIfPossible(0.2, random, () -> zombie.setBaby(true));
    EquipmentFitter.equipArmor(zombie, random);
    zombie.setCanBreakDoors(true);
    EntityUtil.modifyAttribute(zombie, GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(
      "zombie.damage",
      3 + random.nextInt(7),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(zombie, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "zombie.speed",
      random.nextDouble() / 4.4,
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(zombie, ZOMBIE_SPAWN_REINFORCEMENTS, new EntityAttributeModifier(
      "zombie.reinforcements",
      1,
      EntityAttributeModifier.Operation.ADDITION
    ));
  };

  public static final EntityInitializer<ZombieEntity> ZOMBIE_USE_TOOL = (zombie, random) -> {
    ZOMBIE_BASE.initialize(zombie, random);
    EquipmentFitter.equipTool(zombie, random);
    EntityUtil.addExperiencePoints(zombie, random.nextInt(5));
  };

  public static final EntityInitializer<ZombieEntity> ZOMBIE_USE_WEAPON = (zombie, random) -> {
    ZOMBIE_BASE.initialize(zombie, random);
    EquipmentFitter.equipWeapon(zombie, random);
    EntityUtil.addExperiencePoints(zombie, 3 + random.nextInt(7));
  };

  public static final EntityInitializer<ZombieVillagerEntity> ZOMBIE_VILLAGER = (zombieVillager, random) -> {
    ZOMBIE_USE_WEAPON.initialize(zombieVillager, random);
    VillagerProfession profession = Registry.VILLAGER_PROFESSION.getRandom(random).get().value();
    VillagerType type = Util.getRandom(VillagerTypeAccessor.getBiomeTypeToIdMap().values().stream().toList(), random);
    VillagerData villagerData = zombieVillager.getVillagerData();
    zombieVillager.setVillagerData(villagerData.withProfession(profession).withType(type).withLevel(RandomUtil.nextInt(1, 5, random)));
    if (VillagerProfession.LIBRARIAN.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.LIBRARIAN(random).toNbt());
    } else if (VillagerProfession.CLERIC.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.CLERIC(random).toNbt());
    } else if (VillagerProfession.ARMORER.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.ARMORER(random).toNbt());
    } else if (VillagerProfession.WEAPONSMITH.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.WEAPONSMITH(random).toNbt());
    } else if (VillagerProfession.TOOLSMITH.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.TOOLSMITH(random).toNbt());
    } else if (VillagerProfession.BUTCHER.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.BUTCHER(random).toNbt());
    } else if (VillagerProfession.FISHERMAN.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.FISHERMAN(random).toNbt());
    } else if (VillagerProfession.FARMER.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.FARMER(random).toNbt());
    } else if (VillagerProfession.LEATHERWORKER.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.LEATHERWORKER(random).toNbt());
    } else if (VillagerProfession.SHEPHERD.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.SHEPHERD(random).toNbt());
    } else if (VillagerProfession.MASON.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.MASON(random).toNbt());
    } else if (VillagerProfession.FLETCHER.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.FLETCHER(random).toNbt());
    } else if (VillagerProfession.CARTOGRAPHER.equals(profession)) {
      zombieVillager.setOfferData(ZombieVillagerTradeOffers.CARTOGRAPHER(random).toNbt());
    }
  };

  public static final EntityInitializer<DrownedEntity> DROWNED = (drowned, random) -> {
    ZOMBIE_BASE.initialize(drowned, random);
    EquipmentFitter.equipTrident(drowned, random);
    EquipmentFitter.equipTurtleHelmet(drowned, random);
    EntityUtil.addExperiencePoints(drowned, 6 + random.nextInt(7));
  };

  public static final EntityInitializer<MagmaCubeEntity> MAGMA_CUBE = (magma, random) -> {
    ((MagmaCubeEntityAccessor) magma).invokeSetSize(RandomUtil.nextInt(4, 12, random), true);
    ((ISlimeEntity) magma).setLowJump(true);
    ((ISlimeEntity) magma).setPreventSplitSize(RandomUtil.nextInt(4, 5, random));
    ((ISlimeEntity) magma).setAttackSpeed(RandomUtil.nextInt(8, 19, random));
    EntityUtil.equipStackAndSetDropChance(
      magma, EquipmentSlot.CHEST, EnchantmentUtil.enchant(
        new ItemStack(Items.NETHERITE_CHESTPLATE),
        MoreEnchantmentsMod.RETALIATION, RandomUtil.nextInt(3, 7, random)
      ), 0.1F
    );
    EntityUtil.modifyAttribute(magma, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "Magma Max Health",
      RandomUtil.nextInt(magma.getSize(), magma.getSize() * 11, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(magma, GENERIC_MAX_HEALTH, new EntityAttributeModifier(
      "Magma Speed",
      1.5 + random.nextFloat(),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
  };

  public static final EntityInitializer<GuardianEntity> GUARDIAN = (guardian, random) -> {
    EntityUtil.modifyAttribute(guardian, GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(
      "Mandala Guardian Damage",
      RandomUtil.nextInt(10, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(guardian, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "Mandala Guardian Speed",
      1 + random.nextFloat(),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    RandomUtil.runIfPossible(0.4, random, () -> guardian.addStatusEffect(new StatusEffectInstance(StatusEffects.INVISIBILITY, 1, 999999)));
    ((IGuardianEntity) guardian).setWarmupTime(RandomUtil.nextInt(5, 30, random));
  };

  public static final EntityInitializer<ElderGuardianEntity> ELDER_GUARDIAN = (elderGuardian, random) -> {
    EntityUtil.modifyAttribute(elderGuardian, GENERIC_ATTACK_DAMAGE, new EntityAttributeModifier(
      "Mandala Guardian Damage",
      RandomUtil.nextInt(7, 20, random),
      EntityAttributeModifier.Operation.ADDITION
    ));
    EntityUtil.modifyAttribute(elderGuardian, GENERIC_MOVEMENT_SPEED, new EntityAttributeModifier(
      "Mandala Guardian Speed",
      1.1 + random.nextFloat(),
      EntityAttributeModifier.Operation.MULTIPLY_TOTAL
    ));
    RandomUtil.runIfPossible(0.6, random, () -> elderGuardian.addStatusEffect(new StatusEffectInstance(StatusEffects.RESISTANCE, RandomUtil.nextInt(4, random), 999999)));
    ((IGuardianEntity) elderGuardian).setWarmupTime(RandomUtil.nextInt(3, 15, random));
  };

  public static <T extends MobEntity> EntityInitializer<T> discardChance(double chance) {
    return (mob, random) -> RandomUtil.runIfPossible(chance, random, mob::discard);
  }

}
